﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CommServer.Tasks.Common
{
    public abstract class ATimingTask
    {
        protected bool m_Stop = true;

        //任务有效开始时间
        private DateTime StartTime = DateTime.Now;
        //任务有效结束时间
        private DateTime EndTime = new DateTime(2030, 1, 1);

        //第一次执行时间
        private DateTime m_FirstExcuteTime;
        public DateTime FirstExcuteTime
        {
            set
            {
                m_FirstExcuteTime = value;
                SetTaskFirstExcuteTime();
            }
        }
        //执行间隔(0表示只执行一次，以后 不在执行)
        private int m_Interval = 0;
        public int Interval
        {
            set
            {
                m_Interval = value;
                SetTaskFirstExcuteTime();
            }
            get
            {
                return m_Interval;
            }
        }
        //间隔单位
        private IntervalUnit m_Unit = IntervalUnit.Day;
        public IntervalUnit Unit
        {
            set
            {
                m_Unit = value;
                SetTaskFirstExcuteTime();
            }
        }
        //下次应该执行的时间
        private DateTime NextExcuteTime;
        
        private void SetTaskNextExcuteTime()
        {
            switch (m_Unit)
            {
                case IntervalUnit.Day:
                    NextExcuteTime = NextExcuteTime.AddDays(m_Interval);
                    break;
                case IntervalUnit.Month:
                    NextExcuteTime = NextExcuteTime.AddMonths(m_Interval);
                    break;
                case IntervalUnit.Hour:
                    NextExcuteTime = NextExcuteTime.AddHours(m_Interval);
                    break;
                case IntervalUnit.Minute:
                    NextExcuteTime = NextExcuteTime.AddMinutes(m_Interval);
                    break;
                case IntervalUnit.Second:
                    NextExcuteTime = NextExcuteTime.AddSeconds(m_Interval);
                    break;
                case IntervalUnit.Year:
                    NextExcuteTime = NextExcuteTime.AddYears(m_Interval);
                    break;
            }
        }

        private void SetTaskFirstExcuteTime()
        {
            DateTime CurTime = DateTime.Now;
            switch (m_Unit)
            {
                case IntervalUnit.Day:
                    NextExcuteTime = new DateTime(CurTime.Year, CurTime.Month, CurTime.Day, m_FirstExcuteTime.Hour, m_FirstExcuteTime.Minute, m_FirstExcuteTime.Second);
                    break;
                case IntervalUnit.Month:
                    NextExcuteTime = new DateTime(CurTime.Year, CurTime.Month, m_FirstExcuteTime.Day, m_FirstExcuteTime.Hour, m_FirstExcuteTime.Minute, m_FirstExcuteTime.Second);
                    break;
                case IntervalUnit.Hour:
                    NextExcuteTime = new DateTime(CurTime.Year, CurTime.Month, CurTime.Day, CurTime.Hour, m_FirstExcuteTime.Minute, m_FirstExcuteTime.Second);
                    break;
                case IntervalUnit.Minute:
                    NextExcuteTime = new DateTime(CurTime.Year, CurTime.Month, CurTime.Day, CurTime.Hour, CurTime.Minute, m_FirstExcuteTime.Second);
                    break;
                case IntervalUnit.Second:
                    NextExcuteTime = new DateTime(CurTime.Year, CurTime.Month, CurTime.Day, CurTime.Hour, CurTime.Minute, CurTime.Second);
                    break;
                case IntervalUnit.Year:
                    NextExcuteTime = new DateTime(CurTime.Year, m_FirstExcuteTime.Month, m_FirstExcuteTime.Day, m_FirstExcuteTime.Hour, m_FirstExcuteTime.Minute, m_FirstExcuteTime.Second);
                    break;
            }
            if (NextExcuteTime < CurTime)
            {
                SetTaskNextExcuteTime();
            }
        }

        public void Start()
        {
            m_Stop = false;
            Task.Run(() =>
            {
                //等待到整分差1秒
                int Seconds = 59 - DateTime.Now.Second;
                DateTime StandardTime = new DateTime(2015, 1, 1);
                for (int i = 0; i < 100 * Seconds; i++)
                {
                    if (m_Stop)
                    {
                        return;
                    }
                    Thread.Sleep(10);
                }
                Task.Run(() =>
                {
                    while (true)
                    {
                        //等待一秒
                        for (int i = 0; i < 100; i++)
                        {
                            if (m_Stop)
                            {
                                return;
                            }
                            Thread.Sleep(10);
                        }
                        //任务执行时间不在有效时间内
                        if (NextExcuteTime < StartTime || NextExcuteTime > EndTime)
                        {
                            continue;
                        }
                        //不在执行时间
                        double CurTime = (DateTime.Now - StandardTime).TotalSeconds;
                        double TaskTime = (NextExcuteTime - StandardTime).TotalSeconds;
                        if (CurTime < TaskTime)
                        {
                            continue;
                        }
                        //计算任务下次执行时间
                        SetTaskNextExcuteTime();
                        //执行任务(耗时任务自己使用线程处理)
                        Task.Run(() =>
                        {
                            Excute();
                        });
                        
                    }
                });
            });
        }
        public void Stop()
        {
            m_Stop = true;
            Thread.Sleep(50);
        }

        public abstract void Excute();
    }
}
